// 换肤
import cssVars from 'css-vars-ponyfill'
import store from '@/store'

/**
 * 初始化主题变量
 */
export function initThemeCssVariables() {
  const theme = store.state.settings.theme
  const themeList = store.state.settings.themeList
  const themeColorAux = themeList[11]
  const themeColorAux1 = themeList[7]
  const themeColorAux2 = themeList[12]
  const variableObj = {
    '--themeColor': theme,
    '--themeColorAux': themeColorAux,
    '--themeColorAux1': themeColorAux1,
    '--themeColorAux2': themeColorAux2
  }
  cssVars({
    preserveStatic: false,
    variables: (variableObj)
  })
}

const data = {
  chalk: '',
  theme: '', // 主题颜色
  blobHref: ''
}

/**
 * 更换主题 https://panjiachen.github.io/vue-element-admin-site/zh/guide/advanced/theme.html#动态换肤
 */
export async function initTheme() {
  const val = localStorage.getItem('theme_mall') || '#2F68FD'

  const ORIGINAL_THEME = '#409EFF' // element-ui default theme color

  data.theme = localStorage.getItem('theme_mall') || ORIGINAL_THEME

  const oldVal = data.chalk ? data.theme : ORIGINAL_THEME
  if (typeof val !== 'string') return
  const themeCluster = getThemeCluster(val.replace('#', ''))

  // 在此处理生成的辅助色 ↓↓↓
  let themeList = [].concat(themeCluster)
  themeList = formatThemeList(themeList)
  // 在此处理生成的辅助色 ↑↑↑

  try {
    store.dispatch('settings/changeThemeList', themeList)
  } catch {
    // console.error('颜色保存出错，请重试')
  }
  const originalCluster = getThemeCluster(oldVal.replace('#', ''))

  /**
   * 替换element-ui主题
   * @param {*} variable
   * @param {*} id
   * @returns
   */
  const getHandler = (variable, id) => {
    return () => {
      const originalCluster = getThemeCluster(ORIGINAL_THEME.replace('#', ''))
      const newStyle = updateStyle(data[variable], originalCluster, themeCluster)
      try {
        let linkTag = document.getElementById(id)
        const newElementStyleBlob = new Blob([newStyle], { type: 'text/css' })
        const urlObject = window.URL || window.webkitURL || window
        if (data.blobHref) {
          window.URL.revokeObjectURL(data.blobHref)
        }
        const href = urlObject.createObjectURL(newElementStyleBlob)
        // console.log(href, 'href')
        data.blobHref = href
        if (!linkTag) {
          linkTag = document.createElement('link')
          linkTag.setAttribute('id', id)
          linkTag.setAttribute('rel', 'stylesheet')
          const styles = document.head.querySelectorAll('style')
          document.head.insertBefore(linkTag, styles[0])
        }
        linkTag.setAttribute('href', href)
      } catch {
        console.error('element-ui替换出错，请重试')
      }
    }
  }

  if (!data.chalk) {
    // public/elementui/element@2.13.0.css
    const url = `${process.env.BASE_URL}elementui/element@2.13.0.css`
    await getCSSString(url, 'chalk')
  }

  const chalkHandler = getHandler('chalk', 'theme-style')

  chalkHandler()

  const styles = [].slice.call(document.querySelectorAll('style'))
    .filter(style => {
      const text = style.innerText
      return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
    })
  // console.log(styles, 'styles')
  styles.forEach(style => {
    const { innerText } = style
    if (typeof innerText !== 'string') return
    // 替换css
    style.innerText = updateStyle(innerText, originalCluster, themeCluster)
  })
}

/**
 * 处理themeList
 * @param {*} themeList
 */
function formatThemeList(themeList) {
  themeList[0] = `#${themeList[0]}`

  // 调整顺序，颜色由深到浅
  const c = themeList[11]
  themeList.splice(11, 1)
  themeList.unshift(c)

  // 5个预置颜色的辅助色$themeColorAux, 使用预置的辅助色
  if (data.theme === '#2F68FD') {
    themeList[11] = '#EEF4FF'
  } else if (data.theme === '#E60027') {
    themeList[11] = '#FFEDED'
  } else if (data.theme === '#FF5A1F') {
    themeList[11] = '#FFF2EC'
  } else if (data.theme === '#CC9756') {
    themeList[11] = '#FFFAF2'
  } else if (data.theme === '#13B7CF') {
    themeList[11] = '#ECF9FB'
  }

  // $themeColorAux 转 rgba, 透明度 0.5
  const c11 = themeList[11]
  const red = parseInt(c11.slice(1, 3), 16)
  const green = parseInt(c11.slice(3, 5), 16)
  const blue = parseInt(c11.slice(5, 7), 16)
  themeList.push(`rgba(${red}, ${green}, ${blue}, 0.5)`)

  return themeList
}

function updateStyle(style, oldCluster, newCluster) {
  let newStyle = style
  oldCluster.forEach((color, index) => {
    newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
  })
  return newStyle
}

function getCSSString(url, variable) {
  return new Promise(resolve => {
    const xhr = new XMLHttpRequest()
    xhr.onreadystatechange = () => {
      if (xhr.readyState === 4 && xhr.status === 200) {
        data[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
        resolve()
      }
    }
    xhr.open('GET', url)
    xhr.send()
  })
}

/**
 * 计算辅助色
 * @param {*} theme
 * @returns
 */
function getThemeCluster(theme) {
  const tintColor = (color, tint) => {
    let red = parseInt(color.slice(0, 2), 16)
    let green = parseInt(color.slice(2, 4), 16)
    let blue = parseInt(color.slice(4, 6), 16)

    if (tint === 0) { // when primary color is in its rgb space
      return [red, green, blue].join(',')
    } else {
      red += Math.round(tint * (255 - red))
      green += Math.round(tint * (255 - green))
      blue += Math.round(tint * (255 - blue))

      red = red.toString(16)
      green = green.toString(16)
      blue = blue.toString(16)

      return `#${red}${green}${blue}`
    }
  }

  /**
   * 得到一个深色
   * @param {*} color
   * @param {*} shade
   * @returns
   */
  const shadeColor = (color, shade) => {
    let red = parseInt(color.slice(0, 2), 16)
    let green = parseInt(color.slice(2, 4), 16)
    let blue = parseInt(color.slice(4, 6), 16)

    red = Math.round((1 - shade) * red)
    green = Math.round((1 - shade) * green)
    blue = Math.round((1 - shade) * blue)

    // 当主题色较深时, 某个色会是F, 不能正确拼接成6位颜色, 所以, 不足两位时, 前面补0
    red = red.toString(16).padStart(2, '0')
    green = green.toString(16).padStart(2, '0')
    blue = blue.toString(16).padStart(2, '0')

    return `#${red}${green}${blue}`
  }

  const clusters = [theme]
  for (let i = 0; i <= 9; i++) {
    clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
  }
  clusters.push(shadeColor(theme, 0.1))
  return clusters
}

